﻿#pragma once

#include <iostream>
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <functional>
#include <stdexcept>

class CThreadPool
{
public:

	//构造函数  不能发生隐式类型转换 线程数量为系统推荐值
	explicit CThreadPool(size_t threads = std::thread::hardware_concurrency());
	~CThreadPool();

    template<class F, class... Args>
    auto EnQueue(F&& f, Args&&... args);
        // ->std::future<typename std::result_of<F(Args...)>::type>;

	void Stop();

private:
	std::vector<std::thread> m_vecWorkers;
	std::queue<std::function<void()>> m_queTasks;
	std::mutex m_queue_mutex;
	std::condition_variable m_condition;
	bool m_stop;
};

template<typename F, typename ...Args>
auto CThreadPool::EnQueue(F&& f, Args && ...args)
{
	//获取f的返回值类型
	using return_type = std::invoke_result_t<F, Args...>;

	//std::packaged_task<return_type()> package(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
	//auto task = std::make_shared<package>;

	auto task = std::make_shared<std::packaged_task<return_type()>> (
		std::bind(std::forward<F>(f), std::forward<Args>(args)...) 
    );// 完美转发，构造任务仿函数的指针

	// 异步获得函数执行的future返回
	std::future<return_type> res = task->get_future();     

	{
		std::unique_lock<std::mutex> lock(this->m_queue_mutex);

		if (m_stop)
		{
			throw std::runtime_error("enqueue on stopped Thread pool");
		}

		m_queTasks.emplace([task = std::move(task)](){
			(*task)();
		});
	}

	m_condition.notify_one();
	return res;

}

// template<class F, class... Args>
// auto CThreadPool::enqueue(F&& f, Args&&... args)
// -> std::future<typename std::result_of<F(Args...)>::type>
// {
//     using return_type = typename std::result_of<F(Args...)>::type;

//     auto task = std::make_shared< std::packaged_task<return_type()> >(
//         std::bind(std::forward<F>(f), std::forward<Args>(args)...)
//         );

//     std::future<return_type> res = task->get_future();
//     {
//         std::unique_lock<std::mutex> lock(m_queue_mutex);

//         if (m_stop)
//             throw std::runtime_error("enqueue on stopped ThreadPool");

//         m_queTasks.emplace([task]() { (*task)(); });
//     }
//     m_condition.notify_one();
//     return res;
// }
